
/*BSP*/
#include "IO.h"
#include "Bsp_Delay.h"

/*Util*/
#include "Bit.h"
#include "Buffer.h"

#include "FreeRTOS.h"
#include "task.h"

#include "ID_Process.h"

#define FREQ_MHz(n)	((uint32_t)1000000 * (n))

#if 0
#define ID_TIMER				TIMER0
#define ID_TIMER_Freq			10000000

#define ID_TIMER_Delay(us)		\
do{	\
    TIMER0->CMP = (us) * 72; \
    TIMER0->CTL = TIMER_CTL_CNTEN_Msk | TIMER_ONESHOT_MODE | 0;	\
	__NOP();  __NOP(); __NOP();\
	while(TIMER0->CTL & TIMER_CTL_ACTSTS_Msk);	\
}while(0);
#endif 


#define ID_TIMER_Delay(us)	BSP_StrictDelay_us(us)


#define ID_SDA_GP		GPIOB
#define ID_SDA_Pin		GPIO_PIN_9

#define ID_SCL_GP		GPIOB
#define ID_SCL_Pin		GPIO_PIN_8

#define ID_TX_GP		GPIOA
#define ID_TX_Pin		GPIO_PIN_0

#define ID_RX_GP		GPIOA
#define ID_RX_Pin		GPIO_PIN_1

#define ID_SCL_Set(s)	BSP_IO_Set(ID_SCL_GP, ID_SCL_Pin, s)
#define ID_SCL_Get()	BSP_IO_Get(ID_SCL_GP, ID_SCL_Pin)
#define ID_SCL_Mode(mode)	BSP_IO_SetMode(ID_SCL_GP, ID_SCL_Pin, mode)
#define ID_SCL_Idle()	BSP_IO_Set(ID_SCL_GP, ID_SCL_Pin, 1)

#define ID_SDA_Set(s)	BSP_IO_Set(ID_SDA_GP, ID_SDA_Pin, s)
#define ID_SDA_Get()	BSP_IO_Get(ID_SDA_GP, ID_SDA_Pin)
#define ID_SDA_Mode(mode)	BSP_IO_SetMode(ID_SDA_GP, ID_SDA_Pin, mode)
#define ID_SDA_Idle()	BSP_IO_Set(ID_SDA_GP, ID_SDA_Pin, 1)

#define ID_RX_Set(s)	BSP_IO_Set(ID_RX_GP, ID_RX_Pin, s)
#define ID_TX_Get()		BSP_IO_Get(ID_TX_GP, ID_TX_Pin)

#define ID_SCL_Delay()	ID_TIMER_Delay(4)
#define ID_NopDelay()	do{	\
		NP();  NP(); NP(); NP();  NP(); NP();	\
	}while(0)

static const IO_T ID_SDA = IO_INIT_TABLE(ID_SDA_GP, ID_SDA_Pin);
static const IO_T ID_SCL = IO_INIT_TABLE(ID_SCL_GP, ID_SCL_Pin);
static const IO_T ID_TxFrame = IO_INIT_TABLE(ID_TX_GP, ID_TX_Pin);
static const IO_T ID_RxFrame = IO_INIT_TABLE(ID_RX_GP, ID_RX_Pin);

void ID_I2C_Test(void);

void ID_I2C_Init(void){
	IO_Init(&ID_SDA, IO_Mode_OD);
	IO_Init(&ID_SCL, IO_Mode_OD);
	ID_SDA_Idle();
	ID_SCL_Idle();
	
	IO_Init(&ID_TxFrame, IO_Mode_IPU);
	IO_Init(&ID_RxFrame, IO_Mode_OUT);
	BSP_IO_Set(ID_RX_GP, ID_RX_Pin, 0);
	
    nvic_irq_enable(EXTI0_IRQn, 0U, 0U);

    /* connect key EXTI line to key GPIO pin */
    gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOA, GPIO_PIN_SOURCE_0);

    /* configure key EXTI line */
    exti_init(EXTI_0, EXTI_INTERRUPT, EXTI_TRIG_RISING);
    exti_interrupt_flag_clear(EXTI_0);

}

static int ID_I2C_SendByte(uint8_t byte){
	uint32_t i;
	uint32_t bit;
	
	for(i = 0; i < 8; i++)
	{
		bit = byte & (0x80 >> i) ? 1 : 0;
		ID_SCL_Set(0);
		ID_TIMER_Delay(2);		
		ID_SDA_Set(bit);
		ID_TIMER_Delay(2);
		ID_SCL_Set(1);
		ID_SCL_Delay();
	}
	//receive ack
	ID_SCL_Set(0);
	ID_NopDelay();
	ID_TIMER_Delay(3);
	ID_SCL_Set(1);
	ID_NopDelay();
	bit = ID_SDA_Get();
	ID_SCL_Delay();
	return bit;
}

int ID_I2C_Send(const uint8_t buf[], uint32_t len){
	uint32_t i;
	int ack = 0;
	
	taskENTER_CRITICAL();
	{
	//start condittion
	ID_SCL_Set(1);
	ID_SDA_Set(1);	
	ID_RX_Set(1);
 	ID_SCL_Delay();
 	ID_SDA_Set(0);
	ID_SCL_Delay();
	
	//send data
	for(i = 0; i < len; i++){
		ID_SDA_Set(ack);
		ack = ID_I2C_SendByte(buf[i]);
		if(ack != 0){
			break;
		}
	}
	
	//stop condittion	
	ID_SDA_Set(ack);
 	ID_SCL_Set(0);
	ID_TIMER_Delay(2);
 	ID_SDA_Set(0);
 	ID_TIMER_Delay(1);
	ID_SCL_Set(1);
	ID_TIMER_Delay(1);
	ID_SDA_Set(1);
	ID_TIMER_Delay(1);
	ID_RX_Set(0);
	
	}
	ID_SDA_Idle();
	ID_SCL_Idle();
	taskEXIT_CRITICAL();	
	return ack;
}

static int ID_I2C_ReceiveByte(void){
    uint32_t i;
    uint32_t bit;
    uint8_t byte = 0;
    volatile uint32_t clock = 0;    

    for(i = 0; i < 8; i++)
    {
    	clock = 0;
        while(ID_SCL_Get() != 0) {
            if(ID_TX_Get() == 0){
                return 0x100;
            }
            if(++clock > 7200){
                return 0xFF01;
            }
        }
        //SCL = 0 NOW
		clock = 0;
        while(ID_SCL_Get() == 0) {
            if(ID_TX_Get() == 0){
                return 0x100;
            }
            if(++clock > 7200){
                return 0xFF01;
            }
        }
		//SCL = 1 NOW		
        bit = ID_SDA_Get();
        if(bit != 0){
            byte |= 0x80 >> i;
        }
    }

    //	send ack
    ID_SDA_Set(bit);

	clock = 0;
	while(ID_SCL_Get() != 0) {
		if(ID_TX_Get() == 0){
			return 0x100;
		}
		if(++clock > 7200){
			return 0xFF01;
		}
	}
	
	//SCL = 0 NOW
    ID_SDA_Set(0);
	clock = 0;
	while(ID_SCL_Get() == 0) {
		if(ID_TX_Get() == 0){
			return 0x100;
		}
		if(++clock > 7200){
			return 0xFF01;
		}
	}
	//SCL = 1 NOW	

	clock = 0;
	while(ID_SCL_Get() != 0) {
		if(ID_TX_Get() == 0){
			return 0x100;
		}
		if(++clock > 7200){
			return 0xFF01;
		}
	}
	ID_SDA_Idle();
    return byte;
}

int ID_I2C_Receive(uint16_t max, uint8_t buf[], uint16_t *len){
	int byte;
	uint32_t i = 0;	
	
	while(ID_TX_Get() != 0){
		byte = ID_I2C_ReceiveByte();
		if(byte < 0x100){
			if(i < max){
				buf[i++] = (uint8_t)byte;
			}
		}
		else
		if(byte > 0x100){
			return byte;
		}
	}
	*len = i;
	return 0;
}

extern volatile uint8_t idFlags;
extern Buffer_T idI2cBuffer;

#if 0
void GPD_IRQHandler(void)
{
    if(GPIO_GET_INT_FLAG(PD, BIT2)){
    	int ret;
    	
        GPIO_CLR_INT_FLAG(PD, BIT2);
        idI2cBuffer.length = 0;
        ret = ID_I2C_Receive(275, idI2cBuffer.buffer, &idI2cBuffer.length);
        if(!ret){
			//Bit_set(idFlags, 1);
			ID_I2C_Notify();
        }
    }
    else{
        /* Un-expected interrupt. Just clear all interrupts */
        PD->INTSRC = PD->INTSRC;
    }
}
#endif 

void EXTI0_IRQHandler(void)
{
    if (RESET != exti_interrupt_flag_get(EXTI_0)) {
		int ret;
		
        exti_interrupt_flag_clear(EXTI_0);
		idI2cBuffer.length = 0;
		ret = ID_I2C_Receive(275, idI2cBuffer.buffer, &idI2cBuffer.length);
		if(!ret){
			ID_I2C_Notify();
		}
    }
}


#include "BSP_Delay.h"

void ID_I2C_Test(void){
	uint8_t testData[] = {1, 2, 3, 4,
						5, 6, 7, 8,
						9, 0, 0xA, 0xB, 
						0xC, 0xD, 0xE, 0xF
						};
	while(1){
		ID_I2C_Send(testData, sizeof(testData));
#if 0
		BSP_Delay_ms(100);
//			ID_RX_Set(0);
		PD3 = 0;
		BSP_Delay_ms(100);
		//ID_RX_Set(1);
		PD3 = 1;
#endif 
		BSP_Delay_ms(100);
	}
}

